依賴注入這個主題大概就可以寫五天了吧(?),這個系列就不多作介紹了,詳細的可以參考英文微基,網路上也有很多相關文章 (其實是自己講不清楚)。今天會針對如何在 ASP.NET Core 中使用依賴注入作介紹。
開始註冊服務之前,我們先來了解服務的生命周期。註冊服務時需設定生命周期,有三種生命周期設定:
Startup.ConfigureSerivces 中註冊時提供新的實例。之後每次被注入時都會使用同一個實例。如果應用程式中需要 Singleton 行為,建議讓服務容器來管理其生命周期,不要自己實作。看這麼多字,不如用範例來比較一下不同生命周期的差異吧!我們以唯一識別碼「OperationId」來代表不同的工作,並觀察使用不同生命周期註冊服務時的差異。參考完整原始碼
首先建立不同介面代表不同生命周期設定的類型:
public interface IOperation
{
    Guid OperationId { get; }
}
public interface IOperationTransient : IOperation
{
}
public interface IOperationScoped : IOperation
{
}
public interface IOperationSingleton : IOperation
{
}
public interface IOperationSingletonInstance : IOperation
{
}
建立 Operation 類別來實作這些介面。建構元會傳入一個 GUID,如果沒有傳入則會建立一個新的 GUID:
public class Operation :
        IOperationTransient,
        IOperationScoped,
        IOperationSingleton,
        IOperationSingletonInstance
{
    public Operation() : this(Guid.NewGuid())
    {
    }
    public Operation(Guid id)
    {
        OperationId = id;
    }
    public Guid OperationId { get; }
}
新增一個相依四種 Operation 類型的 OperationService 類別:
public class OperationService
{
    public OperationService(
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance instanceOperation)
    {
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = instanceOperation;
    }
    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }
}
在 Startup.ConfigureServices 方法中,以不同的生命周期設定,將服務新增到服務容器中:
public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();
    services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));
    services.AddTransient<OperationService, OperationService>();
}
新增一個 DependencyInjectionLifetimesController 控制器類別,注入上面建立的這些服務,並新增一個 Index Action,把被注入的服務都加到 ViewBag 中以在 View 中使用。
public class DependencyInjectionLifetimesController : Controller
{
    private readonly IOperationTransient _transientOperation;
    private readonly IOperationScoped _scopedOperation;
    private readonly IOperationSingleton _singletonOperation;
    private readonly IOperationSingletonInstance _singletonInstanceOperation;
    private readonly OperationService _operationService;
    public DependencyInjectionLifetimesController(IOperationTransient transientOperation, IOperationScoped scopedOperation, IOperationSingleton singletonOperation, IOperationSingletonInstance singletonInstanceOperation, OperationService operationService)
    {
        _transientOperation = transientOperation;
        _scopedOperation = scopedOperation;
        _singletonOperation = singletonOperation;
        _singletonInstanceOperation = singletonInstanceOperation;
        _operationService = operationService;
    }
    // GET: /<controller>/
    public IActionResult Index()
    {
        ViewBag.Transient = _transientOperation;
        ViewBag.Scoped = _scopedOperation;
        ViewBag.Singleton = _singletonOperation;
        ViewBag.SingletonInstance = _singletonInstanceOperation;
        ViewBag.Service = _operationService;
        return View();
    }
}
最後,建立 DependencyInjectionLifetimes/Index.cshtml,對應到 Controller/Action 的 View:
@{
    ViewData["Title"] = "Dependency Injection Lifetimes Example";
}
<style>
    table tr td {
        padding: 5px;
    }
    table tr td:first-child {
        text-align: right;
        font-weight: bold;
    }
</style>
<h2>生命周期範例</h2>
<hr />
<h3>Controller Operations</h3>
<table>
    <tr>
        <td>Transient</td>
        <td>@ViewBag.Transient.OperationId</td>
    </tr>
    <tr>
        <td>Scoped</td>
        <td>@ViewBag.Scoped.OperationId</td>
    </tr>
    <tr>
        <td>Singleton</td>
        <td>@ViewBag.Singleton.OperationId</td>
    </tr>
    <tr>
        <td>SingletonInstance</td>
        <td>@ViewBag.SingletonInstance.OperationId</td>
    </tr>
</table>
<hr />
<h3>OperationService Operations</h3>
<table>
    <tr>
        <td>Transient</td>
        <td>@ViewBag.Service.TransientOperation.OperationId</td>
    </tr>
    <tr>
        <td>Scoped</td>
        <td>@ViewBag.Service.ScopedOperation.OperationId</td>
    </tr>
    <tr>
        <td>Singleton</td>
        <td>@ViewBag.Service.SingletonOperation.OperationId</td>
    </tr>
    <tr>
        <td>SingletonInstance</td>
        <td>@ViewBag.Service.SingletonInstanceOperation.OperationId</td>
    </tr>
</table>
執行應用程式後,用瀏覽器開兩個分頁觀察 OperationId 在兩次請求的差異: